/**
 * Copyright (C) 2011 Andrew C. Love (DNC) <dnc.app.sup@gmail.com>
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.dnc.cloak.service;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.OutputStream;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.sql.DataSource;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRExporterParameter;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.export.JRXlsExporter;
import net.sf.jasperreports.engine.export.JRXlsExporterParameter;

import org.apache.log4j.Logger;

import com.dnc.cloak.framework.context.Context;
import com.dnc.cloak.framework.report.ReportRequest;
import com.dnc.cloak.framework.service.AbstractService;
import com.dnc.cloak.framework.service.ServiceException;
import com.dnc.cloak.framework.util.file.FileLoader;
import com.dnc.cloak.service.gen.ReportDefinitionService;

public class ReportServiceImpl extends AbstractService implements ReportService {

    private static final Logger logger = Logger.getLogger(ReportServiceImpl.class.getName());

    private static final String PARM_FORMAT_EXCEL = "PARM_FORMAT_EXCEL";
    private static Map<String,JasperReport> compiledReports = new TreeMap<String,JasperReport>();
    
    private DataSource dataSource;
    private ReportDefinitionService reportDefinitionService;
    private SecurityService securityService;   
    
    public DataSource getDataSource() {
        return dataSource;
    }

    public void setDataSource(DataSource dataSource) {
        this.dataSource = dataSource;
    }
    
    public ReportDefinitionService getReportDefinitionService() {
        return reportDefinitionService;
    }

    public void setReportDefinitionService(
            ReportDefinitionService reportDefinitionService) {
        this.reportDefinitionService = reportDefinitionService;
    }    
    

    public SecurityService getSecurityService() {
        return securityService;
    }

    public void setSecurityService(SecurityService securityService) {
        this.securityService = securityService;
    }

    public void requestReport(Context context,List<ReportRequest> requests) throws ServiceException {
        
        for(ReportRequest request : requests){
            requestReport(context,request);
        }
        
    }

    public void requestReport(Context context,ReportRequest request) throws ServiceException {


        try {
            long begin = new Date().getTime();
            logger.debug("Begin requestReport");
            logger.debug(request.getReportTemplate());

            String templateName = request.getReportTemplate();
            JasperReport jreport = null;

            if (compiledReports.containsKey(templateName)){
                logger.debug("Report definition is cached" + templateName);
                jreport = compiledReports.get(templateName);
            }
            else {
                logger.debug("Report definition is not cached" + templateName);

                //First try to look for a compiled report
                try {
                    int pos = templateName.lastIndexOf('.');
                    String compiledReportName = templateName.substring(0,pos + 1) + "jasper";
                    logger.info("Attempting to load pre compiled report:" + compiledReportName);
                    ObjectInputStream compiledReportStream = new ObjectInputStream(getClass().getResourceAsStream(compiledReportName));
                    jreport = (JasperReport) compiledReportStream.readObject();
                    compiledReportStream.close();
                    compiledReports.put(templateName, jreport);
                }
                catch (Exception e) {
                    logger.error(e.getMessage(),e);
                    //Since a compiled report was not found, try to compile it
                    logger.info("Attempting to load report template:" + templateName);
                    InputStream templateStream = getClass().getResourceAsStream(templateName);
                    jreport = JasperCompileManager.compileReport(templateStream);
                    templateStream.close();
                    compiledReports.put(templateName, jreport);
                }
            }

            
            logger.debug("Filling report with data");
            
            JasperPrint jasperPrint = JasperFillManager.fillReport(jreport, request.getParameters(),dataSource.getConnection());

            if (request.getParameters().containsKey(PARM_FORMAT_EXCEL) &&
                    ((Boolean)request.getParameters().get(PARM_FORMAT_EXCEL)).booleanValue() == true){
                try {
                    String fileName = request.getReportLocation() + request.getReportName() + ".xls" ;
                    logger.debug("fileName:" + fileName);

                    File file = new File(fileName);
                    file.getParentFile().mkdirs();
                    if (file.exists()) {
                        file.delete();
                        file.createNewFile();
                    }
                    file.getParentFile().mkdirs();

                    JRXlsExporter exporter = new JRXlsExporter();
                    OutputStream ouputStream = new FileOutputStream(file);
                    ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                    exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
                    exporter.setParameter(JRXlsExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
                    exporter.setParameter(JRXlsExporterParameter.IS_ONE_PAGE_PER_SHEET, Boolean.FALSE);
                    exporter.setParameter(JRXlsExporterParameter.IS_REMOVE_EMPTY_SPACE_BETWEEN_ROWS, Boolean.TRUE);
                    exporter.setParameter(JRXlsExporterParameter.IS_DETECT_CELL_TYPE, Boolean.TRUE);
                    exporter.setParameter(JRXlsExporterParameter.IS_WHITE_PAGE_BACKGROUND, Boolean.FALSE);
                    exporter.setParameter(JRXlsExporterParameter.CHARACTER_ENCODING, "UTF-8");
                    exporter.setParameter(JRXlsExporterParameter.IS_IGNORE_GRAPHICS, Boolean.TRUE);
                    exporter.exportReport();
                    ouputStream.write(byteArrayOutputStream.toByteArray());
                    ouputStream.flush();
                    ouputStream.close();
                    request.setReportResponse(byteArrayOutputStream.toByteArray());

                }
                catch (Exception e) {
                    throw new ServiceException(e);
                }
                catch (Throwable e) {
                    throw new ServiceException(e);
                }
            }
            else {
                String fileName = request.getReportLocation() + request.getReportName() + ".pdf" ;
                logger.debug("fileName:" + fileName);

                File file = new File(fileName);
                file.getParentFile().mkdirs();

                if (file.exists()) {
                    file.delete();
                    file.createNewFile();
                }

                JasperExportManager.exportReportToPdfFile(jasperPrint, fileName);
                FileLoader fileLoader = new FileLoader(file);

                request.setReportResponse(fileLoader.getByteArray());
            }

            long end = new Date().getTime();

            logger.debug("End requestReport: duration= " + (end-begin));

        }
        catch (SQLException e) {
            throw new ServiceException(e);
        }
        catch (JRException e) {
            throw new ServiceException(e);
        }
        catch (FileNotFoundException e) {
            throw new ServiceException(e);
        }
        catch (IOException e) {
            throw new ServiceException(e);
        }
//        finally {
//            try {
//                d.getSqlMapClient().endTransaction();
//            }
//            catch (SQLException e) {
//                logger.error("requestReport",e);
//            }
//        }
    }
   
}
